package solver

import (
	"fmt"
	"log"
	"slices"
	"time"
)

type Check bool

var CHECK Check

func (c *Check) Open() {
	*c = true
}

func (c *Check) Close() {
	*c = false
}

func (c *Check) Doing() bool {
	return bool(*c)
}

var CHECK_POINTS []int

func (g *Grid) prepareStrategies() {
	if len(g.strategies) != 0 {
		return
	}

	g.strategies = []Strategy{
		g.LastOneBox,
		g.LastOneRow,
		g.LastOneCol,
		g.HiddenSingleBox,
		g.HiddenSingleRow,
		g.HiddenSingleCol,
		g.NakedSingle,
		g.Pointing,
		g.Claiming,
		g.HiddenPair,
		g.NakedPair,
		g.HiddenTriple,
		g.NakedTriple,
		g.HiddenQuandruple,
		g.NakedQuadruple,
		g.RectangleElimination,
		g.XWing,
		g.Swordfish,
		g.Jellyfish,
		g.FinnedXWing,
		g.FinnedSwordfish,
		g.FinnedJellyfish,
		g.Skycraper,
		g.TwoStringKite,
		g.TurbotFish,
		g.XYWing,
		g.XYZWing,
		g.WXYZWing,
		g.VWXYZWing,
		g.WWing,
		g.SuedeCoq1,
		g.SuedeCoq2,
		g.UniqueRectangleType1,
		g.UniqueRectangleType2A,
		g.UniqueRectangleType2B,
		g.UniqueRectangleType3A,
		g.UniqueRectangleType3B,
		g.UniqueRectangleType4A,
		g.UniqueRectangleType4B,
		g.UniqueRectangleType4C,
		g.UniqueRectangleXYZWing,
		g.UniqueRectangleWXYZWing,
		g.AvoidRectangleType1,
		g.AvoidRectangleType2A,
		g.AvoidRectangleType3A,
		g.AvoidRectangleType3B,
		g.AlmostLockedPair,
		g.AlmostLockedSubsetType2,
		g.AlmostLockedSubsetType3,
		g.AlmostLockedSubsetType4,
		g.AlmostLockedSubsetType5,
		g.AlmostLockedSubsetType6,
		g.BinaryUniversalGrave1,
		g.BinaryUniversalGrave2,
		g.BinaryUniversalGraveN,
		g.BinaryUniversalGrave3Naked,
		g.BinaryUniversalGrave3Hidden,
		g.BinaryUniversalGrave4,
		g.BinaryUniversalGraveXZ,
		g.RemotePair,
		g.XYChain,
		g.XCycle1,
		g.XCycle2,
		g.XCycle3,
		g.AlmostLockedSetsXZDouble,
		g.AlmostLockedSetsXZ,
	} //
}

func (g *Grid) Solve() {
	if len(g.strategies) == 0 {
		g.prepareStrategies()
	}
	used := false
	n := 1
	log.SetPrefix(fmt.Sprintf("%4d ", n))
	for g.solvedCount != 81 {
		for _, strategy := range g.strategies {
			used = strategy()
			if used {
				//fmt.Println("CHECK", bool(CHECK), CHECK.Doing())
				if CHECK.Doing() && slices.Contains(CHECK_POINTS, n) {
					h, m, s := time.Now().Clock()
					fileName := fmt.Sprintf("%ssudoku%04d%02d%02d%02d.json",
						"/Users/zoushengyuan/Downloads/", n, h, m, s)
					g.WriteDrawJson(fileName)
					fileName = fmt.Sprintf("%ssudoku%04d%02d%02d%02d.png",
						"/Users/zoushengyuan/Downloads/", n, h, m, s)
					g.DrawGrid(fileName)
					//fmt.Println("CHECK", bool(CHECK), CHECK.Doing())

				}
				n++
				log.SetPrefix(fmt.Sprintf("%4d ", n))
				//fmt.Println(n)
				break
			}
		}

		if !used {
			break
		}
		used = false
	}
	log.SetPrefix("Sudoku:")
}

func (g *Grid) SolveForBack() {
	if len(g.strategies) == 0 {
		g.prepareStrategies()
	}
	used := false
	for g.solvedCount != 81 {
		for _, strategy := range g.strategies {
			used = strategy()
			if used {
				break
			}
		}

		if !used {
			break
		}
		used = false
	}
}
